﻿/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef GAME_SERVER_OPCODEHANDLER_H_
#define GAME_SERVER_OPCODEHANDLER_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

/************************************************************************/
/* 操作码处理程序                                                         */
/************************************************************************/

#include <cstdint>
#include <boost/unordered_map.hpp>
#include <NodeCpp/Singleton.h>
#include "Shared/WorldPacket.h"
using NodeCpp::Singleton;

enum SessionStatus
{
	STATUS_AUTHED = 0,                     ///< Player authenticated (_player==NULL, m_playerRecentlyLogout = false or will be reset before handler call)
	STATUS_LOGGEDIN,                       ///< Player in game (_player!=NULL, inWorld())
	STATUS_TRANSFER,                       ///< Player transferring to another map (_player!=NULL, !inWorld())
	STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout)
	STATUS_NEVER,                          ///< Opcode not accepted from client (deprecated or server side only)
	STATUS_UNHANDLED                       ///< We don' handle this opcode yet
};

enum ePacketProcessing
{
	PROCESS_INPLACE = 0,   ///< process packet whenever we receive it - mostly for non-handled or non-implemented packets
	PROCESS_THREADUNSAFE,  ///< packet is not thread-safe - process it in \ref World::UpdateSessions
	PROCESS_THREADSAFE     ///< packet is thread-safe - process it in \ref Map::Update
};

class WorldSession;

struct OpcodeHandler
{
	char const* Name;                                   /* 操作码名字 */
	SessionStatus Status;                               /* 执行该操作码处理程序时需要的Session状态 */
	ePacketProcessing PacketProcessing;                  /* 操作码处理程序执行方式 */
	void (WorldSession::*Handler)(WorldPacket&);        /* 操作码处理程序 */
};

typedef boost::unordered_map<std::uint16_t, struct OpcodeHandler>	OpHandlerMap;

class OpCodes
{
public:
	OpCodes(void);
	~OpCodes(void);

	void BuildOpcodeList(void);
	void StoreOpcode(std::uint16_t _Opcode, char const* _Name, SessionStatus _Status,
		ePacketProcessing _Process, void (WorldSession::*_Handler)(WorldPacket&))
	{
		struct OpcodeHandler& _Ref = OpHandlers_[_Opcode];
		_Ref.Name = _Name;
		_Ref.Status = _Status;
		_Ref.PacketProcessing = _Process;
		_Ref.Handler = _Handler;
	}

    /* 查找操作码处理程序 */
	OpcodeHandler const* LookupOpcode(std::uint16_t _ID) const
	{
		OpHandlerMap::const_iterator _Iter = OpHandlers_.find(_ID);
		if (_Iter != OpHandlers_.end()) {
			return &_Iter->second;
		}
		return NULL;
	}

	OpcodeHandler const& operator[](std::uint16_t _ID) const
	{
		OpHandlerMap::const_iterator _Iter = OpHandlers_.find(_ID);
		if (_Iter != OpHandlers_.end()) {
			return _Iter->second;
		}
		return EmptyHandler_;
	}

private:
	OpHandlerMap OpHandlers_;
	const static OpcodeHandler EmptyHandler_;
};

#define sOpCodes	Singleton<OpCodes>::Instance()

/* 查找操作码名字 */
inline const char* LookupOpcodeName(std::uint16_t _ID)
{
	if (OpcodeHandler const* _Op = sOpCodes.LookupOpcode(_ID)) {
		return _Op->Name;
	}
	return "received unknown opcode, it's more than max!";
}

#endif /* GAME_SERVER_OPCODEHANDLER_H_ */
